#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <functional>

#include "epoll.hpp"
#include "connection.hpp"
#include "log.hpp"

using namespace log_namespace;

// Reactor的核心工作：
// 1. 管理connection 和对应的内核事件
// 2. 事件派发
class Reactor
{
    static const int gnum = 64;

public:
    Reactor()
        :_epoll(std::make_unique<Epoll>())
        ,_isrunning(false)
    {
    }

    void AddConnection(int fd, uint32_t events, const inetAddr &addr, int type)
    {
        // 1. 构建一个connection
        myConnection *con = new myConnection(fd);
        con->setEvents(events);
        con->setConnectionType(type);
        con->setAddr(addr);
        con->setReactor(this); // 将当前对象设置进入所有的con对象中

        // 设置对该connection的上层处理，
        if (con->getConnectionType() == ListenConnection)
        {
            con->registerHandler(_OnConnect, nullptr, nullptr);
        }
        else
        {
            con->registerHandler(_OnRecevr, _OnSender, _OnExcept);
        }
        
        // 2. 将fd 和 events 托管给epoll
        if (!_epoll->addEvent(con->getsocketfd(), con->getEvents()))
        {
            return;
        }

        // 3. 将新的connection托管给 _connection
        _connections.insert(std::make_pair(fd, con));
    }

    void EnableConnectiontforReadandWrite(int socketfd, bool readable, bool writeable)
    {
        if (!isConnectionExist(socketfd))
        {
            return;
        }
        uint32_t events = ((readable ? EPOLLIN : 0) |(writeable ? EPOLLOUT : 0) | EPOLLET);
        _connections[socketfd]->setEvents(events);

        _epoll->ModiEvent(_connections[socketfd]->getsocketfd(), _connections[socketfd]->getEvents());
    }

    // 客户端关闭连接，则关闭连接
    void DelConnection(int socketfd)
    {
        // 0. 安全检查
        if (!isConnectionExist(socketfd))
        {
            return;
        }

        LOG(INFO, "sockfd %d quit, 服务器释放所有资源\n", socketfd);
        // 1. 在内核中移除对socketfd的关心()
        EnableConnectiontforReadandWrite(socketfd, false, false);
        _epoll->DelEvent(socketfd);
        // 2. 关闭socketfd
        _connections[socketfd]->close();
        // 3. 在Reactor中移除对Connection的关心
        delete _connections[socketfd];
        _connections.erase(socketfd);
    }

    void loopOnce(int timeout)
    {
        int n = _epoll->wait(revs, gnum, timeout);
        for (int i = 0; i < n; i++)
        {
            int ssockfd = revs[i].data.fd;
            uint32_t revents = revs[i].events;

            // 如果出现的事件是 错误  或  挂断
            // 统一按照 输入输出事件处理
            if (revents & EPOLLERR)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }

            if (revents & EPOLLHUP)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }

            if (revents & EPOLLIN)
            {
                if (isConnectionExist(ssockfd) && _connections[ssockfd]->_handler_recver)
                {
                    // 读事件就绪，派发给对应的connection
                    _connections[ssockfd]->_handler_recver(_connections[ssockfd]);
                }
            }

            if (revents & EPOLLOUT)
            {
                if (isConnectionExist(ssockfd) && _connections[ssockfd]->_handler_sender)
                {
                    // 写事件就绪，派发给对应的connection
                    _connections[ssockfd]->_handler_sender(_connections[ssockfd]);
                }
            }
        }
    }

    void Dispatch()
    {
        int timeout = -1;
        _isrunning = true;
        while (_isrunning)
        {
            loopOnce(timeout);
            PrintDebug();
        }
        _isrunning = false;
    }

    bool isConnectionExist(int socketfd)
    {
        return _connections.find(socketfd) != _connections.end();
    }

    void set_OnConnect(handler_t onaccept)
    {
        _OnConnect = onaccept;
    }

    void set_OnNormalHandler(handler_t recver, handler_t sender, handler_t excepter)
    {
        _OnRecevr = recver;
        _OnSender = sender;
        _OnExcept = excepter;
    }

    void PrintDebug()
    {
        std::string fdlist;
        for(auto& conn : _connections)
        {
            fdlist += std::to_string(conn.second->getsocketfd()) + " ";
        }
        LOG(DEBUG, "epoll管理的连接fd列表：%s\n", fdlist.c_str());
    }

    ~Reactor()
    {
    }

private:
    // key: sockfd      value: Connnection
    std::unordered_map<int, myConnection *> _connections;
    std::unique_ptr<Multiplex> _epoll;
    bool _isrunning;
    struct epoll_event revs[gnum];

    // Reactor中添加处理socket的方法集合
    // 1. 处理新链接 套接字
    handler_t _OnConnect;
    // 2. 处理普通的 socketfd，主要是IO处理
    handler_t _OnRecevr;
    handler_t _OnSender;
    handler_t _OnExcept;
};
